/*
 * scheduler.c
 *
 *  Created on: May 29, 2013
 *      Author: Aden
 */
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
#include "global.h"
#include "scheduler.h"
#include "pcb.h"
#include "cpu.h"
#include "process.h"
#include <pthread.h>
pthread_mutex_t lock;

void *run(void *threadID, SchedulerPtr this)
{
	PCBPtr ready_temp;

	long id = (long) threadID;
	printw("THREAD %ld\n", id);
	int i = 1;
	int y = 0;
	for(; i < 1000; i++) {
		pthread_mutex_lock(&lock);
		printw("ReadyQ:[ ");
		for(y = this->pcb->front;  y <= this->pcb->back; y++)
		{
			ready_temp = this->pcb->ready_queue[y];
			printw("P%d ",ready_temp->pid);
			if(ready_temp->pid == 4){
				this->setSchIOQueue(this, ready_temp);
			}
		}
		printw("]\n");

		PCBPtr p = this->dispatcher(this);
		printw("P%d selected from queue\n",p->pid);
		p->setState(p, RUNNING);
		p->burst_time--;
		p->proc->no_requests = 4;
		p->toString(p);
		if(p->burst_time == 0){
			printw("P%d has been terminated\n", p->pid);
		}
		if(p->burst_time != 0 ){
			printw("P%d returned to ready queue\n",p->pid);
			this->setSchReadyQueue(this, p);
		}


		pthread_mutex_unlock(&lock);
		sleep(3);
	}

	pthread_exit(NULL);

	return NULL;
}
/*
 * Scheduler constructor
 */
SchedulerPtr newSchedulerConstructor(void){

	SchedulerPtr sch = (SchedulerPtr) malloc(sizeof(SchedulerStr));
	sch->pcb =   newPcbConstructor();
	sch->interrupt = 0;
	sch->io_request = 0;
	sch->time_slice = 0;

	//pointers to function
//	sch->setContextSwitch = setContextSwitch;
	sch->getSchIOQueue = getSchIOQueue;
	sch->setSchIOQueue = setSchIOQueue;
	sch->getSchReadyQueue = getSchReadyQueue;
	sch->setSchReadyQueue = setSchReadyQueue;
	sch->dispatcher = dispatcher;
	//	sch->getJobQueue = getJobQueue;
	//	sch->setJobQueue = setJobQueue;

	return sch;
}
/*
 * Dispatch a process base on the scheduler algorithm type
 * this - the SchedulerPtr
 */
PCBPtr dispatcher(SchedulerPtr this){
	PCBPtr temp = (PCBPtr) malloc(sizeof(PCBStr));
		temp = this->pcb->dequeueReadyQueue(this->pcb);
	return temp;
}

/*
 *Switch process
 *this - the SchedulerPtr
 *interrupt - the interrupt
 *process - the process that is going to be switched
 */
int setContextSwitch(SchedulerPtr this, int interrupt, PCBPtr process){
	switch(interrupt){
	case TIMER_INTERRUPT:
		this->setSchReadyQueue(this, process);
		break;
	case IO_INTERRUPT:
		this->setSchIOQueue(this, process);
		break;
	case KEYBOARD_IO_INTERRUPT:
		this->setSchIOQueue(this, process);
		break;
	case IO_REQ_TRAP:
		this->setSchIOQueue(this, process);
		break;
	default: printw("NO CONTEXT SWITCH\n");
	break;
	}
	return NO_ERROR;
}

/**
 * Add process to scheduler ready queue
 * this - the SchedulerPtr
 * process - the process that is going to be added to ready queue
 */
int setSchReadyQueue(SchedulerPtr this, PCBPtr process){
	this->pcb->setReadyQueue(this->pcb, process);
	return NO_ERROR;
}
/**
 * Return process in scheduler ready queue
 */
PCBPtr getSchReadyQueue(SchedulerPtr this){
	PCBPtr temp;
	temp  = this->pcb->getReadyQueue(this->pcb);
	return temp;
}
/**
 * Add process to scheduler IO queue
 */
int setSchIOQueue(SchedulerPtr this, PCBPtr process){
	this->pcb->setIOQueue(this->pcb, process);
	return NO_ERROR;
}
/**
 * Return process in scheduler IO queue
 */
PCBPtr getSchIOQueue(SchedulerPtr this){
	PCBPtr temp;
	temp  = this->pcb->getIOQueue(this->pcb);
	return temp;
}

/*
int main(void){
	SchedulerPtr s = newSchedulerConstructor();
	PCBPtr p1 = newPcbConstructor();
	PCBPtr p2 = newPcbConstructor();
	PCBPtr p3 = newPcbConstructor();
	PCBPtr p4 = newPcbConstructor();
	PCBPtr p5 = newPcbConstructor();
	PCBPtr p6 = newPcbConstructor();


	p1->createProcess(p1, 1, 10, READY);
	p1->setPriority(p1, 10);
	s->pcb->setReadyQueue(s->pcb, p1);

	p2->createProcess(p2, 2, 2, READY);
	p2->setPriority(p2, 2);
	s->pcb->setReadyQueue(s->pcb, p2);


	p3->createProcess(p3, 3, 3, READY);
	p3->setPriority(p3, 3);
	s->pcb->setReadyQueue(s->pcb, p3);


	p4->createProcess(p4, 4, 4, READY);
	p4->setPriority(p4, 4);
	s->pcb->setReadyQueue(s->pcb, p4);


	p5->createProcess(p5, 5, 5, READY);
	p5->setPriority(p5, 5);
	s->pcb->setReadyQueue(s->pcb, p5);


	p6->createProcess(p6, 6, 6, READY);
	p6->setPriority(p6, 6);
	s->pcb->setReadyQueue(s->pcb, p6);

   // p6 = s->dispatcher(s, 4);
   // printw("P%d",p6->pid);

	//s->pcb->setIOQueue(s->pcb, p6);
	//
	//	PCBPtr w = newPcbConstructor();
	//	w = s->pcb->waiting_queue[0];
	//
	//	printw("WWWW%d",w->pid);


	pthread_t thread_ID[2000];
	int i; void * exit;
	pthread_mutex_init(&lock, NULL);
	for(i = 0;i < 1000; i++)
	{
		pthread_create(&thread_ID[i], NULL, run(NULL, s), NULL);
	}
	for(i = 0;i < 1000; i++)
	{
		pthread_join(thread_ID[i], &exit);
	}


	return 0;
}

// */
